#!/usr/bin/env python
# -*-*- encoding: utf-8 -*-*-
#
#
#
# Copyright 2007-2008 Håvard Gulldahl
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A desktop client for PicasaWeb services."""

import logging

import gdata.photos
import gdata.photos.service

from PyQt4 import QtCore, QtGui

import atom
atom.XML_STRING_ENCODING=None # workaround bug

class PicasaItem(object):
  children = []
  parent = None
  populated = False

  def __init__(self, entry, parent=None):
    self.entry = entry
    self.parent = parent
    if hasattr(entry, 'numphotos'):
      # fill .children with dummy values to get the correct length
      print "length: ", entry.numphotos.text
      self.children = [ PicasaItem(None, self) for j in range(int(entry.numphotos.text)) ]

  def row(self):
    if self.parent:
      return self.parent.children.index(self)
    return 0

  def addChildren(self, objs):
    if not self.populated:
      #wipe dummy values
      self.children = []
    self.children += [PicasaItem(o, self) for o in objs]
    self.populated = True

  def setChildren(self, objs):
    self.children = [PicasaItem(o, self) for o in objs]
    self.populated = True

  def removeChild(self, obj):
    self.children.remove(obj)

class PicasaRoot(PicasaItem):
  def __init__(self):
    pass

class PicasaItemModel(QtCore.QAbstractItemModel):
  root = PicasaRoot()

  def __init__(self):
    QtCore.QAbstractItemModel.__init__(self)
    #self.root = PicasaRoot()

  def doUpdateTopLevel(self, tree):
    self.emit(QtCore.SIGNAL('beginRemoveRows(const QModelIndex & parent, int first, int last)'), QtCore.QModelIndex(), 0, len(self.root.children))
    self.root.setChildren(tree.entry)
    self.emit(QtCore.SIGNAL('endRemoveRows()'))
    #print self.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant(entry.totalResults.text))
    self.emit(QtCore.SIGNAL("layoutChanged()"))

  def doUpdateBranch(self, twig, tree):
    self.emit(QtCore.SIGNAL('beginRemoveRows(const QModelIndex & parent, int first, int last)'), QtCore.QModelIndex(), 0, len(twig.children))
    twig.setChildren(tree.entry)
    self.emit(QtCore.SIGNAL('endRemoveRows()'))
    self.emit(QtCore.SIGNAL("layoutChanged()"))

  def index(self, row, column, parent):
    if row < 0 or column != 0:# or row >= self.rowCount(parent) or column >= self.columnCount(parent):
      return QtCore.QModelIndex()

    if not parent.isValid():
      parentItem = self.root
    else:
      parentItem = parent.internalPointer()

    try:
      childItem = parentItem.children[row]
      return self.createIndex(row, column, childItem)
    except Exception, (e):
      logging.error('bomb! %s', e)
      logging.debug("index: row %s, col %s, parent %s", row, column, parent)
      return QtCore.QModelIndex()

  def parent(self, index):
    if not index.isValid():
      return QtCore.QModelIndex()

    childItem = index.internalPointer()
    if not isinstance(childItem, PicasaItem):
      print childItem, type(childItem)
    parentItem = childItem.parent
    #print "parentItem", parentItem

    if parentItem in (self.root, None):
      return QtCore.QModelIndex()

    return self.createIndex(parentItem.row(), 0, parentItem)

  def child(self, row):
    print "child", row

  def hasChildren(self, idx):
    item = idx.internalPointer()
    if item in (None, self.root):
      return True
    try:
      return isinstance(item.entry, gdata.photos.AlbumEntry)
    except AttributeError:
      return False

  def rowCount(self, parentidx):
    if not parentidx.isValid():
      parent = self.root
    else:
      parent = parentidx.internalPointer()

    #print "rowCount", parentidx, len(parent.children)
    return len(parent.children)

  def columnCount(self, parentidx):
    #print "columnCount", parentidx
    return 1

  def data(self, idx, role):
    #print "data", idx, role

    #The general purpose roles are:
    #Constant	Value	Description
    #Qt::DisplayRole	0	The key data to be rendered (usually text).
    #Qt::DecorationRole	1	The data to be rendered as a decoration (usually an icon).
    #Qt::EditRole	2	The data in a form suitable for editing in an editor.
    #Qt::ToolTipRole	3	The data displayed in the item's tooltip.
    #Qt::StatusTipRole	4	The data displayed in the status bar.
    #Qt::WhatsThisRole	5	The data displayed for the item in "What's This?" mode.
    #Qt::SizeHintRole	13	The size hint for the item that will be supplied to views.


    #Roles describing appearance and meta data:
    #Constant	Value	Description
    #Qt::FontRole	6	The font used for items rendered with the default delegate.
    #Qt::TextAlignmentRole	7	The alignment of the text for items rendered with the default delegate.
    #Qt::BackgroundRole	8	The background brush used for items rendered with the default delegate.
    #Qt::BackgroundColorRole	8	This role is obsolete. Use BackgroundRole instead.
    #Qt::ForegroundRole	9	The foreground brush (text color, typically) used for items rendered with the default delegate.
    #Qt::TextColorRole	9	This role is obsolete. Use ForegroundRole instead.
    #Qt::CheckStateRole	10	This role is used to obtain the checked state of an item (see Qt::CheckState).


    #Accessibility roles:
    #Constant	Value	Description
    #Qt::AccessibleTextRole	11	The text to be used by accessibility extensions and plugins, such as screen readers.
    #Qt::AccessibleDescriptionRole	12	A description of the item for accessibility purposes.


    #User roles:
    #Constant	Value	Description
    #Qt::UserRole	32	The first role that can be used for application-specific purposes.

    if not idx.isValid():
      return QtCore.QVariant()

    item = idx.internalPointer()

    if role == QtCore.Qt.DisplayRole:
      try:
        t = item.entry.title.text.decode('utf8')
      except AttributeError:
        t = "..."
      return QtCore.QVariant(t)
    elif role == QtCore.Qt.DecorationRole:
      try:
        thumb = self.makeThumbnail(item.entry)
        return QtCore.QVariant(thumb)
      except (AttributeError, TypeError):
        return QtCore.QVariant()
    elif role == QtCore.Qt.ToolTipRole:
      try:
        t = "%s (%s)" % (item.entry.summary.text.decode('utf8'), item.entry.timestamp.isoformat())
      except AttributeError:
        t = ''
      return QtCore.QVariant(t)
    #elif role == QtCore.Qt.SizeHintRole:
      #return QtGui.QSize()
    #elif role == QtCore.Qt.CheckStateRole:
      #return None
    else:
      return QtCore.QVariant()

  def flags(self, idx):
    if not idx.isValid():
         return QtCore.Qt.ItemIsEnabled

    return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

  def canFetchMore(self, parent):
    if not parent.isValid():
      return False

    return not parent.internalPointer().populated

  def fetchMore(self, parent):
    if not parent.isValid():
      return

    self.emit(QtCore.SIGNAL('getPhotos(PyQt_PyObject)'), parent.internalPointer() )

  def makeThumbnail(self, entry):
    if not entry.thumbnail:
      return None
    pix = QtGui.QPixmap()
    smallThumbnail = gdata.photos.service.GetSmallestThumbnail(entry.thumbnail)
    pix.loadFromData(self.proxy.photoclient.GetMedia(smallThumbnail.url).file_handle.read())
    icon = QtGui.QIcon(pix)
    print icon
    return icon

  def removeRows(self, row, count, parentidx):
    #A removeRows() implementation must call beginRemoveRows() before the rows are removed from the data structure, and it must call endRemoveRows() immediately afterwards.
    print "removeRows: ", row, count, parentidx
    self.emit(QtCore.SIGNAL('beginRemoveRows(const QModelIndex & parent, int first, int last)'), parentidx, row, row+count)
    success = True
    try:
      parent = parentidx.internalPointer()
      for i in range(row, row+count):
        parent.children.pop(i)
    except Exception,e:
      print 'Removerows:', e
      success = False
    self.emit(QtCore.SIGNAL('endRemoveRows()'))
    self.emit(QtCore.SIGNAL("layoutChanged()"))
    return success

